Skip to main content

A* Algorithm

1. What is A* Algorithm?​

The A* Algorithm is a popular pathfinding and graph traversal algorithm known for its efficiency and accuracy. It is used to find the shortest path from a start node to a goal node by combining the strengths of Dijkstra's Algorithm and Greedy Best-First Search.

2. Algorithm for A* Algorithm​

  1. Initialize the open list with the start node.
  2. Initialize the closed list as empty.
  3. While the open list is not empty:
    • Extract the node with the lowest f-cost from the open list (f-cost = g-cost + h-cost).
    • If this node is the goal node, return the path.
    • Move the node to the closed list.
    • For each neighbor of the current node:
      • If the neighbor is in the closed list, skip it.
      • Calculate the g-cost (distance from start) and h-cost (heuristic estimate to goal).
      • If the neighbor is not in the open list, add it.
      • If the neighbor is in the open list with a higher f-cost, update its f-cost and parent.
  4. If the open list is empty and the goal is not reached, return that no path exists.

3. How Does A* Algorithm Work?​

  • A* uses a priority queue to explore nodes with the lowest f-cost (estimated total cost).
  • The g-cost represents the actual distance from the start node to the current node.
  • The h-cost represents the heuristic estimate from the current node to the goal node.

4. Problem Description​

Given a graph with weighted edges, A* aims to find the shortest path from the start node to the goal node using heuristic estimates.

5. Examples​

Example graph:

      A ---1--- B
| / | \
4 2 5 12
| / | \
C ---1--- D ---1--- E

6. Constraints​

  • The graph can be directed or undirected.
  • The graph may contain cycles.
  • The heuristic function (h-cost) should be admissible (not overestimating the actual cost).

7. Implementation​

A* Algorithm​

import heapq

def heuristic(a, b):
return abs(a - b)

def a_star(graph, start, goal):
open_list = []
heapq.heappush(open_list, (0, start))
came_from = {}
g_cost = {start: 0}
f_cost = {start: heuristic(start, goal)}

while open_list:
_, current = heapq.heappop(open_list)

if current == goal:
path = []
while current in came_from:
path.append(current)
current = came_from[current]
path.append(start)
return path[::-1]

for neighbor, weight in graph[current]:
tentative_g_cost = g_cost[current] + weight
if neighbor not in g_cost or tentative_g_cost < g_cost[neighbor]:
came_from[neighbor] = current
g_cost[neighbor] = tentative_g_cost
f_cost[neighbor] = g_cost[neighbor] + heuristic(neighbor, goal)
heapq.heappush(open_list, (f_cost[neighbor], neighbor))

return []

graph = {
'A': [('B', 1), ('C', 4)],
'B': [('A', 1), ('D', 5), ('E', 12)],
'C': [('A', 4), ('D', 1)],
'D': [('B', 5), ('C', 1), ('E', 1)],
'E': [('B', 12), ('D', 1)]
}

print(a_star(graph, 'A', 'E'))

8. Complexity Analysis​

  • Time Complexity: O(Elog⁑V)O(E \log V) where EE is the number of edges and VV is the number of vertices.
  • Space Complexity: O(V)O(V) due to the priority queue and the g-cost and f-cost dictionaries.

9. Advantages and Disadvantages​

Advantages:​

  • Guarantees finding the shortest path.
  • Efficient with an admissible heuristic.

Disadvantages:​

  • Requires a good heuristic to be efficient.
  • Memory intensive due to maintaining multiple lists and cost dictionaries.

10. References​